#pragma once
#include "../common/dispatcher.hpp"
#include "requestor.hpp"
#include "rpc_caller.hpp"
#include "rpc_registry.hpp"
#include "rpc_topic.hpp"

namespace zl
{
    namespace client
    {
        // 服务注册功能
        // 业务客户端  应用于服务提供者向注册中心进行服务注册
        class RegistryClient
        {
        public:
            using ptr = std::shared_ptr<RegistryClient>;

            // 构造函数传入注册中心的地址信息，用于连接注册中心
            RegistryClient(const std::string &ip, int port)
                : m_requestor(std::make_shared<Requestor>()), m_provider(std::make_shared<client::Provider>(m_requestor)), m_dispatcher(std::make_shared<Dispatcher>())
            {
                // 消息注册
                auto rsp_cb = std::bind(&client::Requestor::onResponse, m_requestor.get(), std::placeholders::_1, std::placeholders::_2);
                m_dispatcher->registerHandler<BaseMessage>(MType::RSP_SERVICE, rsp_cb);

                // 设置客户端连接并注册消息回调函数
                auto message_cb = std::bind(&Dispatcher::onMessage, m_dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                m_client = ClientFactory::create(ip, port);
                m_client->setMessageCallback(message_cb);
                m_client->connect();
            }

            // 向外提供的服务注册接口
            bool registerMethod(const std::string &method, const Address &host)
            {
                return m_provider->registryMethod(m_client->connection(), method, host);
            }

        private:
            zl::client::Requestor::ptr m_requestor;
            zl::client::Provider::ptr m_provider;
            Dispatcher::ptr m_dispatcher;
            zl::BaseClient::ptr m_client;
        };

        // 服务发现功能
        // 业务客户端  应用于服务调用者从注册中心进行服务发现
        class DiscoveryClient
        {
        public:
            using ptr = std::shared_ptr<DiscoveryClient>;

            DiscoveryClient(const std::string &ip, int port, const Discoverer::offlinCallback &offline_callback)
                : m_requestor(std::make_shared<Requestor>()), m_discoverer(std::make_shared<client::Discoverer>(m_requestor, offline_callback)), m_dispatcher(std::make_shared<Dispatcher>())
            {
                // 消息注册
                auto rsp_cb = std::bind(&client::Requestor::onResponse, m_requestor.get(), std::placeholders::_1, std::placeholders::_2);
                m_dispatcher->registerHandler<BaseMessage>(MType::RSP_SERVICE, rsp_cb);

                auto req_cb = std::bind(&client::Discoverer::onServiceRequest, m_discoverer.get(), std::placeholders::_1, std::placeholders::_2);
                m_dispatcher->registerHandler<ServiceRequest>(MType::REQ_SERVICE, req_cb);

                auto message_cb = std::bind(&Dispatcher::onMessage, m_dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                m_client = ClientFactory::create(ip, port);
                m_client->setMessageCallback(message_cb);
                m_client->connect();
            }

            // 向外提供服务发现接口
            bool serviceDiscover(const std::string &method, Address &host)
            {
                return m_discoverer->serviceDiscover(m_client->connection(), method, host);
            }

        private:
            zl::client::Requestor::ptr m_requestor;
            zl::client::Discoverer::ptr m_discoverer;
            Dispatcher::ptr m_dispatcher;
            zl::BaseClient::ptr m_client;
        };

        // 基础rpc功能
        class RpcClient
        {
        public:
            using ptr = std::shared_ptr<RpcClient>;
            RpcClient(bool enable_discovery, const std::string &ip, int port)
                : _enable_discovery(enable_discovery), _requestor(std::make_shared<Requestor>()), _dispatcher(std::make_shared<Dispatcher>()), _rpc_caller(std::make_shared<RpcCaller>(_requestor))
            {
                // 针对rpc请求后的响应进行的回调处理
                auto rsp_cb = std::bind(&client::Requestor::onResponse, _requestor.get(), std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_RPC, rsp_cb);

                // 如果启用了服务发现，地址信息是注册中心的地址，是服务发现客户端需要连接的地址，则通过地址信息实例化discovery_client
                // 如果没有启用服务发现，则地址信息是服务提供者的地址，则直接实例化好rpc_client
                if (_enable_discovery)
                {
                    auto offline_callback = std::bind(&RpcClient::delClient, this, std::placeholders::_1);
                    _discovery_client = std::make_shared<DiscoveryClient>(ip, port, offline_callback);
                }
                else
                {
                    auto message_cb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                    _rpc_client = ClientFactory::create(ip, port);
                    _rpc_client->setMessageCallback(message_cb);
                    _rpc_client->connect();
                }
            }

            bool call(const std::string &method, const Json::Value &params, Json::Value &result)
            {
                // 获取服务提供者：1. 服务发现；  2. 固定服务提供者
                BaseClient::ptr client = getClient(method);
                if (client.get() == nullptr)
                {
                    return false;
                }

                // 3. 通过客户端连接，发送rpc请求
                return _rpc_caller->call(client->connection(), method, params, result);
            }

            bool call(const std::string &method, const Json::Value &params, RpcCaller::JsonAsyncResponce &result)
            {
                // 获取服务提供者：1. 服务发现；  2. 固定服务提供者
                BaseClient::ptr client = getClient(method);
                if (client.get() == nullptr)
                {
                    return false;
                }

                // 3. 通过客户端连接，发送rpc请求
                return _rpc_caller->call(client->connection(), method, params, result);
            }

            bool call(const std::string &method, const Json::Value &params, const RpcCaller::JsonResponseCallback &cb)
            {
                // 获取服务提供者：1. 服务发现；  2. 固定服务提供者
                BaseClient::ptr client = getClient(method);
                if (client.get() == nullptr)
                {
                    return false;
                }

                // 3. 通过客户端连接，发送rpc请求
                return _rpc_caller->call(client->connection(), method, params, cb);
            }

        private:
            BaseClient::ptr newClient(const Address &host)
            {
                auto message_cb = std::bind(&Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                auto client = zl::ClientFactory::create(host.first, host.second);
                client->setMessageCallback(message_cb);
                client->connect();

                putClient(host, client);
                return client;
            }

            BaseClient::ptr getClient(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _rpc_clients.find(host);
                if (it != _rpc_clients.end())
                {
                    return it->second;
                }
                return BaseClient::ptr();
            }

            BaseClient::ptr getClient(const std::string method)
            {
                BaseClient::ptr client;

                if (_enable_discovery)
                {
                    // 1. 通过服务发现，获取服务提供者地址信息
                    Address host;
                    bool ret = _discovery_client->serviceDiscover(method, host);
                    if (ret == false)
                    {
                        ELOG("当前 %s 服务，没有找到服务提供者！", method.c_str());
                        return BaseClient::ptr();
                    }

                    // 2. 查看服务提供者是否已有实例化客户端，有则直接使用，没有则创建
                    client = getClient(host);
                    if (client.get() == nullptr)
                    {
                        client = newClient(host);
                    }
                }
                else
                {
                    client = _rpc_client;
                }

                return client;
            }

            void putClient(const Address &host, BaseClient::ptr &client)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _rpc_clients.insert(std::make_pair(host, client));
            }

            void delClient(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _rpc_clients.erase(host);
            }

        private:
            struct AddressHash
            {
                size_t operator()(const Address &addr) const
                {
                    std::string addrstring = addr.first + std::to_string(addr.second);
                    return std::hash<std::string>{}(addrstring);
                }
            };

        private:
            bool _enable_discovery;
            DiscoveryClient::ptr _discovery_client;
            Requestor::ptr _requestor;
            RpcCaller::ptr _rpc_caller;
            Dispatcher::ptr _dispatcher;
            zl::BaseClient::ptr _rpc_client; // 未启用服务发现时使用
            std::mutex _mutex;
            //<"127.0.0.1:8080", client1>
            std::unordered_map<Address, BaseClient::ptr, AddressHash> _rpc_clients; // 用于服务发现的客户端连接池
        };

        class TopicClient
        {
        public:
            using ptr = std::shared_ptr<TopicClient>;

            // 构造函数传入注册中心的地址信息，用于连接注册中心
            TopicClient(const std::string &ip, int port)
                : m_requestor(std::make_shared<Requestor>()), m_topic_manager(std::make_shared<TopicManager>(m_requestor)), m_dispatcher(std::make_shared<Dispatcher>())
            {
                // 消息注册
                auto rsp_cb = std::bind(&client::Requestor::onResponse, m_requestor.get(), std::placeholders::_1, std::placeholders::_2);
                m_dispatcher->registerHandler<BaseMessage>(MType::RSP_TOPIC, rsp_cb);

                auto msg_cb = std::bind(&TopicManager::onPublish, m_topic_manager.get(),
                                        std::placeholders::_1, std::placeholders::_2);
                m_dispatcher->registerHandler<TopicRequest>(MType::REQ_TOPIC, msg_cb);

                // 设置客户端连接并注册消息回调函数
                auto message_cb = std::bind(&Dispatcher::onMessage, m_dispatcher.get(), std::placeholders::_1, std::placeholders::_2);
                m_client = ClientFactory::create(ip, port);
                m_client->setMessageCallback(message_cb);
                m_client->connect();
            }

            // 向外提供的服务注册接口

            bool create(const std::string &key)
            {
                return m_topic_manager->create(m_client->connection(), key);
            }

            bool remove(const std::string &key)
            {
                return m_topic_manager->remove(m_client->connection(), key);
            }
            bool cancel(const std::string &key)
            {
                return m_topic_manager->cancel(m_client->connection(), key);
            }
            bool publish(const std::string &key, const std::string &msg)
            {
                return m_topic_manager->publish(m_client->connection(), key, msg);
            }
            bool subscribe(const std::string &key, const TopicManager::SubCallback &cb)
            {
                return m_topic_manager->subscribe(m_client->connection(), key, cb);
            }

            void shutdown()
            {
                m_client->shutdown();
            }

        private:
            Requestor::ptr m_requestor;
            TopicManager::ptr m_topic_manager;
            Dispatcher::ptr m_dispatcher;
            BaseClient::ptr m_client;
        };

    }

}
